本系列同步發表在 個人部落格,歡迎大家關注~
本人在這專案之前是完全沒使用過 GitHub API 的,所以我是以新手之姿來串接它。
如果有理解錯的,希望大家留言告訴我囉~
使用步驟是
小提醒:
接下來我們就直接實際上使用看看。
我先在創建一個新的檔案 lib/services/github_api.dart
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:github/server.dart';
GitHub githubClient = GitHub(
auth: Authentication.withToken(DotEnv().env["GITHUB_PERSONAL_ACCESS_TOKEN"]),
);
主要目的是要宣告出一個全域變數 githubClient
,方便後續其他頁面也能使用。
這裡和昨天一樣我創建了 fetchRepos()
方法,此異步任務的內容是獲取我個人所有的 repo。
接著在 initState()
方法內將 fetchRepos()
assign 給 repoList
,這樣前置作業就算完成拉~
最後比較複雜的部份,我選擇使用 Flutter 原生提供一個方便的 Widget -- FutureBuilder
。
將最主要的內容部份以這個 Widget 來作些改寫,先來看看程式碼。
...
@override
Widget build(BuildContext context) {
return Scrollbar(
child: RefreshIndicator(
child: FutureBuilder(
future: repoList,
builder:
(BuildContext context, AsyncSnapshot<List<Repository>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
if (!snapshot.hasError) {
return ListView.separated(
padding: EdgeInsets.all(0.0),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
"${snapshot.data[index].owner.login}/${snapshot.data[index].name}"),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 8.0),
snapshot.data[index].description != null
? Text(snapshot.data[index].description)
: Text("No description provided."),
SizedBox(height: 8.0),
Text("★ ${snapshot.data[index].stargazersCount}"),
],
),
trailing: snapshot.data[index].language != null
? Text(snapshot.data[index].language)
: SizedBox(),
contentPadding: EdgeInsets.symmetric(
vertical: 8.0, horizontal: 16.0),
onTap: () {},
);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(height: 0.0),
);
} else {
return Center(child: Text("No Data"));
}
break;
case ConnectionState.none:
case ConnectionState.active:
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
}
},
),
onRefresh: () async {
await Future.delayed(Duration(seconds: 1));
setState(() {
repoList = fetchRepos();
});
},
),
);
}
Future<List<Repository>> fetchRepos() async {
...
}
程式碼看起來很長,但最主要的概念就是我將原本 ListView.separated
的部份包進了 FutureBuilder
裡。
而使用 FutureBuilder
有兩大重點:
future
屬性需要帶入你要執行的異步任務(這裡就是指獲取 repos)builder
屬性需要填入你所想要創建的內容,而執行異步任務完的結果,可以在函數第二個參數 AsyncSnapshot snapshot
來作使用。小提醒:
- 使用
FutureBuilder
其實還有一個好處,可以在build
裡面處理snapshot.connectionState
,比如有 連線異常 或 載入資料中的情況,能直接用 switch case 切換 Widget 來表示這些狀態。- 在開發途中發現如果搭配
FutureBuilder
,RefreshIndicator.onRefresh
的使用上需作些調整。(參考: HOW TO REFRESH FUTUREBUILDER ON BUTTON CLICK IN FLUTTER)- 關於 Personal access token 我使用
flutter_dotenv
這套件來載入我的.env
設定檔,主要是為些安全上作考量囉~
--
今日成果
鐵人賽默默的也過了一半了~
這幾天小弟較忙,原諒小弟今天先以簡短的內容做收~
請問一下 .env 檔案的設定部分該怎麼處理呢?
DotEnv().env['xxx'] 回傳都是Null ..
你的 .env 檔是放在哪呢? 另外在 main.dart 的 main() 需要先 await DotEnv().load('.env');